package cn.ljw.mybatis;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.*;
import java.util.Date;

/**
 * @author
 * @date 2024/9/21
 * @Code 面向注解面向卿，终无解释再无你
 * @description 默认的 SqlSession 工厂设计模式
 */

@Data
public class WinterFlySqlSession implements SqlSession {
    private Configuration configuration;
    private Connection connection;
    private Map<String, XNode> mapperElement;
    private boolean autoCommit;

    public WinterFlySqlSession( Connection connection, Map<String, XNode> mapperElement, boolean autoCommit) {

        this.connection = connection;
        this.mapperElement = mapperElement;
        this.autoCommit = autoCommit;
    }

    //    private LjwConnection ljwConnection;
    public WinterFlySqlSession(Connection connection, Map<String, XNode> mapperElement) {
    this.connection = connection;
    this.mapperElement = mapperElement;
}

    /**
     * 结果处理器对结果集进行封装
     *
     * @param resultSet 结果集
     * @param clazz     结果类型
     * @param <T>       泛型类型
     * @return 封装后的结果列表
     */
    @SneakyThrows
    private <T> List<T> resultHandler(ResultSet resultSet, Class<?> clazz) {
        List<T> list = new ArrayList<>();
        ResultSetMetaData metaData = resultSet.getMetaData();
        int columnCount = metaData.getColumnCount();
        // 遍历每一行
        while (resultSet.next()) {
            T obj = (T) clazz.getDeclaredConstructor().newInstance();
            for (int i = 1; i <= columnCount; i++) { // 获取每一列
                Object value = resultSet.getObject(i); // 获取列值
                String columnName = metaData.getColumnName(i); // 获取列名
                String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                Method method;
                if (value instanceof Timestamp) {
                    method = clazz.getMethod(setMethod, Date.class);
                } else {
                    method = clazz.getMethod(setMethod, value.getClass());
                }
                method.invoke(obj, value);
            }
            list.add(obj);
        }
        return list;
    }

    /**
     * 构造参数
     *
     * @param preparedStatement 预编译语句
     * @param parameter         参数对象
     * @param parameterMap      参数映射
     * @throws SQLException
     * @throws IllegalAccessException
     */
    private void buildParameter(PreparedStatement preparedStatement, Object parameter, Map<Integer, String> parameterMap) throws SQLException, IllegalAccessException {

        int size = parameterMap.size();
        // 单个参数
        if (parameter instanceof Long) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setLong(i, Long.parseLong(parameter.toString()));
            }
            return;
        }

        if (parameter instanceof Integer) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setInt(i, Integer.parseInt(parameter.toString()));
            }
            return;
        }

        if (parameter instanceof String) {
            for (int i = 1; i <= size; i++) {
                preparedStatement.setString(i, parameter.toString());
            }
            return;
        }

        Map<String, Object> fieldMap = new HashMap<>();
        // 对象参数
        Field[] declaredFields = parameter.getClass().getDeclaredFields();
        for (Field field : declaredFields) {
            String name = field.getName();
            field.setAccessible(true);
            Object obj = field.get(parameter);
            field.setAccessible(false);
            fieldMap.put(name, obj);
        }

        for (int i = 1; i <= size; i++) {
            String parameterDefine = parameterMap.get(i);
            Object obj = fieldMap.get(parameterDefine);

            if (obj instanceof Short) {
                preparedStatement.setShort(i, Short.parseShort(obj.toString()));
                continue;
            }

            if (obj instanceof Integer) {
                preparedStatement.setInt(i, Integer.parseInt(obj.toString()));
                continue;
            }

            if (obj instanceof Long) {
                preparedStatement.setLong(i, Long.parseLong(obj.toString()));
                continue;
            }

            if (obj instanceof String) {
                preparedStatement.setString(i, obj.toString());
                continue;
            }

            if (obj instanceof Date) {
                preparedStatement.setDate(i, (java.sql.Date) obj);
            }

        }

    }

//    @SneakyThrows
//    @Override
//    public <T> T getMapper(Class<T> type) {
//        // 使用自定义连接获取 Mapper
//        return ljwConnection.getMapper(type);
//    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return null;
    }

    @Override
    public Connection getConnection() {
        return connection;
    }

    /**
     * 携带sql语句执行查询
     *
     * @param statement SQL 语句标识
     * @param <T>       泛型类型
     * @return 查询结果
     */
    @Override
    public <T> T selectOne(String statement) {
        try {
            XNode xNode = mapperElement.get(statement);
            PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
            ResultSet resultSet = preparedStatement.executeQuery();
            List<T> objects = resultHandler(resultSet, Class.forName(xNode.getResultType()));
            return objects.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 携带sql语句和参数执行查询
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param <T>       泛型类型
     * @return 查询结果
     */
    @Override
    @SneakyThrows
    public <T> T selectOne(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
            buildParameter(preparedStatement, parameter, parameterMap);
            ResultSet resultSet = preparedStatement.executeQuery();
            List<T> objects = resultHandler(resultSet, Class.forName(xNode.getResultType()));
            return objects.get(0);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 不带参数的查询列表
     *
     * @param statement SQL 语句标识
     * @param <E>       泛型类型
     * @return 查询结果列表
     */
    @Override
     public <E> List<E> selectList(String statement) {
        XNode xNode = mapperElement.get(statement);
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
            ResultSet resultSet = preparedStatement.executeQuery();
            return resultHandler(resultSet, Class.forName(xNode.getResultType()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 带参数的查询列表
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param <E>       泛型类型
     * @return 查询结果列表
     */
    @Override
    @SneakyThrows
    public <E> List<E> selectList(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        ResultSet resultSet = preparedStatement.executeQuery();
        return resultHandler(resultSet, Class.forName(xNode.getResultType()));
    }

    /**
     * 带参数和分页的查询列表
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param rowBounds 分页参数
     * @param <E>       泛型类型
     * @return 查询结果列表
     */
    @Override
    @SneakyThrows
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        // 设置分页参数
        preparedStatement.setFetchSize(rowBounds.getLimit());
        preparedStatement.setMaxRows(rowBounds.getLimit());
        ResultSet resultSet = preparedStatement.executeQuery();
        // 跳过偏移量
        if (resultSet.absolute(rowBounds.getOffset())) {
            return resultHandler(resultSet, Class.forName(xNode.getResultType()));
        }
        return Collections.emptyList();
    }

    /**
     * 根据指定键将查询结果映射为 Map
     *
     * @param statement SQL 语句标识
     * @param mapKey    映射键
     * @param <K>       键类型
     * @param <V>       值类型
     * @return 映射结果
     */
    @Override
    @SneakyThrows
    public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
        List<V> list = selectList(statement);
        if (list == null || list.isEmpty()) return Collections.emptyMap();

        Map<K, V> resultMap = new HashMap<>();
        for (V item : list) {
            // 假设 mapKey 对应的是对象的某个字段
            Field field = item.getClass().getDeclaredField(mapKey);
            field.setAccessible(true);
            K key = (K) field.get(item);
            resultMap.put(key, item);
        }
        return resultMap;
    }

    /**
     * 根据指定键将带参数的查询结果映射为 Map
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param mapKey    映射键
     * @param <K>       键类型
     * @param <V>       值类型
     * @return 映射结果
     */
    @Override
    @SneakyThrows
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
        List<V> list = selectList(statement, parameter);
        if (list == null || list.isEmpty()) return Collections.emptyMap();

        Map<K, V> resultMap = new HashMap<>();
        for (V item : list) {
            // 假设 mapKey 对应的是对象的某个字段
            Field field = item.getClass().getDeclaredField(mapKey);
            field.setAccessible(true);
            K key = (K) field.get(item);
            resultMap.put(key, item);
        }
        return resultMap;
    }

    /**
     * 根据指定键和分页参数将带参数的查询结果映射为 Map
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param mapKey    映射键
     * @param rowBounds 分页参数
     * @param <K>       键类型
     * @param <V>       值类型
     * @return 映射结果
     */
    @Override
    @SneakyThrows
    public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
        List<V> list = selectList(statement, parameter, rowBounds);
        if (list == null || list.isEmpty()) return Collections.emptyMap();

        Map<K, V> resultMap = new HashMap<>();
        for (V item : list) {
            // 假设 mapKey 对应的是对象的某个字段
            Field field = item.getClass().getDeclaredField(mapKey);
            field.setAccessible(true);
            K key = (K) field.get(item);
            resultMap.put(key, item);
        }
        return resultMap;
    }

    /**
     * 查询游标，不实现具体逻辑
     *
     * @param statement SQL 语句标识
     * @param <T>       泛型类型
     * @return 游标
     */
    @Override
    public <T> Cursor<T> selectCursor(String statement) {
        // 暂不支持
        throw new UnsupportedOperationException("selectCursor 方法尚未实现");
    }

    /**
     * 查询带参数的游标，不实现具体逻辑
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param <T>       泛型类型
     * @return 游标
     */
    @Override
    public <T> Cursor<T> selectCursor(String statement, Object parameter) {
        // 暂不支持
        throw new UnsupportedOperationException("selectCursor 方法尚未实现");
    }

    /**
     * 查询带参数和分页的游标，不实现具体逻辑
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param rowBounds 分页参数
     * @param <T>       泛型类型
     * @return 游标
     */
    @Override
    public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
        // 暂不支持
        throw new UnsupportedOperationException("selectCursor 方法尚未实现");
    }

    /**
     * 插入数据，不带参数
     *
     * @param statement SQL 语句标识
     * @return 受影响的行数
     */
    @Override
    public int insert(String statement) {
        // 暂不支持
        throw new UnsupportedOperationException("insert 方法尚未实现");
    }

    /**
     * 插入数据，带参数
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @return 受影响的行数
     */
    @Override
    @SneakyThrows
    public int insert(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql(), Statement.RETURN_GENERATED_KEYS);
        buildParameter(preparedStatement, parameter, parameterMap);
        int affectedRows = preparedStatement.executeUpdate();
        // 如果需要获取生成的主键，可以在这里处理
        return affectedRows;
    }

    /**
     * 更新数据，不带参数
     *
     * @param statement SQL 语句标识
     * @return 受影响的行数
     */
    @Override
    public int update(String statement) {
        // 暂不支持
        throw new UnsupportedOperationException("update 方法尚未实现");
    }

    /**
     * 更新数据，带参数
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @return 受影响的行数
     */
    @Override
    @SneakyThrows
    public int update(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        return preparedStatement.executeUpdate();
    }

    /**
     * 删除数据，不带参数
     *
     * @param statement SQL 语句标识
     * @return 受影响的行数
     */
    @Override
    public int delete(String statement) {
        // 暂不支持
        throw new UnsupportedOperationException("delete 方法尚未实现");
    }

    /**
     * 删除数据，带参数
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @return 受影响的行数
     */
    @Override
    @SneakyThrows
    public int delete(String statement, Object parameter) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        return preparedStatement.executeUpdate();
    }

    /**
     * 不带参数的查询并处理结果
     *
     * @param statement SQL 语句标识
     * @param handler   结果处理器
     */
    @Override
    @SneakyThrows
    public void select(String statement, Object parameter, ResultHandler handler) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        ResultSet resultSet = preparedStatement.executeQuery();
        List<?> results = resultHandler(resultSet, Class.forName(xNode.getResultType()));
        for (Object obj : results) {
            handler.handleResult((ResultContext) obj);
        }
    }

    /**
     * 不带参数的查询并处理结果
     *
     * @param statement SQL 语句标识
     * @param handler   结果处理器
     */
    @Override
    @SneakyThrows
    public void select(String statement, ResultHandler handler) {
        select(statement, null, handler);
    }

    /**
     * 带参数和分页的查询并处理结果
     *
     * @param statement SQL 语句标识
     * @param parameter 参数
     * @param rowBounds 分页参数
     * @param handler   结果处理器
     */
    @Override
    @SneakyThrows
    public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
        XNode xNode = mapperElement.get(statement);
        Map<Integer, String> parameterMap = xNode.getParameter();
        PreparedStatement preparedStatement = connection.prepareStatement(xNode.getSql());
        buildParameter(preparedStatement, parameter, parameterMap);
        // 设置分页参数
        preparedStatement.setFetchSize(rowBounds.getLimit());
        preparedStatement.setMaxRows(rowBounds.getLimit());
        ResultSet resultSet = preparedStatement.executeQuery();
        // 跳过偏移量
        if (resultSet.absolute(rowBounds.getOffset())) {
            List<?> results = resultHandler(resultSet, Class.forName(xNode.getResultType()));
            for (Object obj : results) {
                handler.handleResult((ResultContext) obj);
            }
        }
    }

    /**
     * 提交事务
     */
    @Override
    @SneakyThrows
    public void commit() {
        connection.commit();
    }

    /**
     * 提交事务，是否强制提交
     *
     * @param force 是否强制提交
     */
    @Override
    @SneakyThrows
    public void commit(boolean force) {
        if (force) {
            connection.commit();
        }
    }

    /**
     * 回滚事务
     */
    @Override
    @SneakyThrows
    public void rollback() {
        connection.rollback();
    }

    /**
     * 回滚事务，是否强制回滚
     *
     * @param force 是否强制回滚
     */
    @Override
    @SneakyThrows
    public void rollback(boolean force) {
        if (force) {
            connection.rollback();
        }
    }

    /**
     * 关闭连接
     */
    @Override
    @SneakyThrows
    public void close() {
        if (connection == null) return;
        connection.close();
    }

    /**
     * 清理缓存
     */
    @Override
    public void clearCache() {
        // 如果有缓存实现，可以在这里清理缓存
    }
}
